﻿using System;
using System.Collections.Generic;
using System.Text;

namespace EC.Application.Impl
{
    using Dapper;
    using Dapper.Contrib.Extensions;
    using EC.Application.Interface;
    using EC.Entity;
    using EC.Entity.Enum;
    using EC.Entity.Query;
    using EC.Entity.Request.IpTable;
    using EC.Entity.Response.IpTable;
    using EC.Entity.Tables;
    using EC.Util;
    using System.Linq;
    using System.Text.Json;

    public class IpTableServiceImpl : IPTableService
    {
        #region 注入
        /// <summary>
        /// 数据接口
        /// </summary>
        private readonly IDBSession _dbSession;

        /// <summary>
        /// 数据库上下文
        /// </summary>
        /// <param name="context">数据库上下文</param>
        public IpTableServiceImpl(IDBSession dbSession)
        {
            _dbSession = dbSession;
        }

        #endregion

        /// <summary>
        /// 白名单缓存分钟数
        /// </summary>
        private readonly int _cacheTime = 9999;

        /// <summary>
        /// 缓存Key前缀
        /// </summary>
        private readonly string _cachePrefix = "Iptable";

        /// <summary>
        /// 多IP分隔符
        /// </summary>
        private readonly char _excision = ',';

        public JResult DelIpTable(int Id)
        {
            var response = new JResult()
            {
                Success = false
            };

            var iptable = _dbSession.DbConnection.QueryFirst<Iptable>($"select * from iptable where Id=@Id", new { Id });
            bool result = _dbSession.DbConnection.Delete(iptable);
            if (!result)
            {
                throw new Exception("删除白名单信息失败.");
            }
            //重置缓存
            ResetCache(iptable.Type);

            response.Success = true;
            response.Message = "操作成功！";

            return response;
        }

        public IpTableResponse Get(int id)
        {
            var ipTableResponse = _dbSession.DbConnection.QueryFirst<IpTableResponse>("select * from iptable where Id=@Id", new { Id = id });
            if (ipTableResponse != null)
            {
                return ipTableResponse;
            }
            return null;
        }

        /// <summary>
        /// 获取白名单
        /// 如果已经缓存则从缓存中获取
        /// </summary>
        /// <param name="systemType"></param>
        /// <returns></returns>
        public IList<IpTableCacheEntity> GetIptable(int systemType)
        {
            string cacheKey = $"{_cachePrefix}{systemType}";

            IList<IpTableCacheEntity> list = InitCache();

            if (!MemoryCacheUtil.Exists(cacheKey))
            {
                var ipLists = _dbSession.DbConnection.Query<IpTableResponse>($"select * from iptable where Type={systemType} and Status=1").ToList();
                foreach (var item in ipLists)
                {
                    //存在多个IP
                    if (item.Ips.Contains(_excision))
                    {
                        var ips = item.Ips.Split(_excision, StringSplitOptions.RemoveEmptyEntries);
                        if (ips.Length > 0)
                        {
                            foreach (var ip in ips)
                            {
                                IpTableCacheEntity entity = new IpTableCacheEntity
                                {
                                    Ip = ip,
                                    Account = item.Account,
                                    GrounpName = item.GrounpName,
                                    Type = item.Type
                                };
                                list.Add(entity);
                            }
                        }
                    }
                    else
                    {
                        IpTableCacheEntity entity = new IpTableCacheEntity
                        {
                            Ip = item.Ips,
                            Account = item.Account,
                            GrounpName = item.GrounpName,
                            Type = item.Type
                        };
                        list.Add(entity);
                    }
                }
                //缓存
                if (list != null && list.Count > 0)
                {
                    string cacheValue = JsonSerializer.Serialize(list);
                    MemoryCacheUtil.Set(cacheKey, cacheValue, _cacheTime);
                }
                return list;
            }
            else
            {
                string cacheValue = MemoryCacheUtil.Get(cacheKey)?.ToString();
                list = JsonSerializer.Deserialize<IList<IpTableCacheEntity>>(cacheValue);
                return list;
            }
        }

        /// <summary>
        /// 必要的IP白名单
        /// 防止数据未添加时本地无法登陆问题
        /// </summary>
        /// <returns></returns>
        private IList<IpTableCacheEntity> InitCache()
        {
            string[] Ips = new string[] { "127.0.0.1", "::1" };

            IList<IpTableCacheEntity> list = new List<IpTableCacheEntity>();
            foreach (var item in EnumUtil.ToDictionary(typeof(SystemType)))
            {
                foreach (var ip in Ips)
                {
                    list.Add(new IpTableCacheEntity
                    {
                        Account = string.Empty,
                        GrounpName = string.Empty,
                        Ip = ip,
                        Type = item.Key
                    });
                }
            }

            return list;
        }

        /// <summary>
        /// 重置缓存
        /// </summary>
        /// <param name="systemType"></param>
        public void ResetCache(int systemType)
        {
            string cacheKey = $"{_cachePrefix}{systemType}";
            if (MemoryCacheUtil.Exists(cacheKey))
            {
                MemoryCacheUtil.Remove(cacheKey);
            }
            //重新缓存
            GetIptable(systemType);
        }

        public DataGrid<IpTableResponse> GetPager(IpTableQuery query)
        {
            var files = "Id,IPS,Type,GrounpName,Account,Remark,Status,CreatedBy,CreatedDate";
            var tableName = "iptable";
            var orderby = "ORDER BY Id DESC";
            var where = "where 1=1 ";

            //查询条件
            DynamicParameters parameters = new DynamicParameters();
            if (!string.IsNullOrEmpty(query.Account))
            {
                where += " and Account  = @Account";
                parameters.Add("Account", query.Account);
            }

            if (!string.IsNullOrEmpty(query.GrounpName))
            {
                where += " and GrounpName = @GrounpName";
                parameters.Add("GrounpName", query.GrounpName);
            }

            if (!string.IsNullOrEmpty(query.Ips))
            {
                where += " and Ips LIKE  @Ips";
                parameters.Add("Ips", "%" + query.Ips + "%");
            }

            if (query.Type > -1)
            {
                where += " and Type = @Type";
                parameters.Add("Type", query.Type);
            }

            if (query.Status.HasValue)
            {
                where += " and Status = @Status";
                parameters.Add("Status", query.Status.Value);
            }

            var sb = new StringBuilder();

            sb.AppendFormat("SELECT COUNT(1) FROM {0} {1};", tableName, where);
            sb.AppendFormat("SELECT {0} FROM {1} {2} {3} LIMIT {4},{5};", files, tableName, where, orderby, (query.Page.Value - 1) * query.Rows.Value, query.Rows.Value);

            using (var multi = _dbSession.DbConnection.QueryMultiple(sb.ToString(), parameters))
            {
                var count = multi.ReadFirst<int>();

                var list = multi.Read<IpTableResponse>();


                return new DataGrid<IpTableResponse>()
                {
                    Total = count,
                    Rows = list,
                    Success = true
                };
            }
        }

        public JResult SaveIpTable(SaveIpTableRequest request)
        {
            var response = new JResult()
            {
                Success = false
            };

            if (string.IsNullOrEmpty(request.Ips))
            {
                throw new Exception("IP信息不能为空.");
            }

            if (request.Type < 0)
            {
                throw new Exception("类型必须选择.");
            }

            if (string.IsNullOrEmpty(request.GrounpName))
            {
                throw new Exception("分组不能为空.");
            }

            if (string.IsNullOrEmpty(request.Account))
            {
                throw new Exception("账号不能为空.");
            }


            //更新
            if (request.Id > 0)
            {
                var iptable = _dbSession.DbConnection.QueryFirst<Iptable>($"select * from iptable where Id=@Id", new { request.Id });
                if (iptable == null)
                {
                    throw new Exception("白名单记录不存在.");
                }

                iptable.Type = request.Type;
                iptable.Ips = request.Ips.Trim();
                iptable.Account = request.Account.Trim();
                iptable.GrounpName = request.GrounpName.Trim();
                iptable.Remark = request.Remark?.Trim();
                iptable.Status = request.Status;
                _dbSession.DbConnection.Update(iptable);

                response.Success = true;
            }
            else
            {
                var iptable = new Iptable()
                {
                    Type = request.Type,
                    Ips = request.Ips.Trim(),
                    Account = request.Account.Trim(),
                    GrounpName = request.GrounpName.Trim(),
                    Remark = request.Remark?.Trim(),
                    Status = request.Status,
                    CreatedBy = request.UserId,
                    CreatedDate = DateTime.Now
                };

                long resultId = _dbSession.DbConnection.Insert(iptable);

                if (resultId <= 0)
                {
                    throw new Exception("新增白名单信息失败.");
                }
                response.Success = true;
            }
            //重置缓存
            ResetCache(request.Type);

            return response;
        }
    }
}
